﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nvigorate.Common;
using Nvigorate.Common.Reflection;
using Nvigorate.Relational.Repository;
using Nvigorate.Relational.State;

namespace Nvigorate.Relational.Repository
{
    public abstract class BaseLazyLoader<T,S>
        where T : class, ITrackState, new()
        where S : class, ITrackState, new()
    {
        protected string _repositoryName;

        public abstract T LoadInstance(S parent);
        public abstract IEnumerable<T> LoadCollection(S parent);

        protected BaseLazyLoader(string repositoryName)
        {
            _repositoryName = repositoryName;
        }
    }

    public class LazyLoadingProxy
    {
        private Type _parentType;
        private Type _childType;
        private Type _loaderType;
        private object _loader;
        private string _repositoryName;
        private static int _lockCounter = 0;

        public static void LockLazyLoading()
        {
            _lockCounter++;
        }

        public static void ReleaseLazyLoading()
        {
            _lockCounter--;
        }

        public static bool DisableLazyLoading 
        { 
            get
            {
                return _lockCounter > 0;
            }
        }

        public object GetChild(ITrackState parent)
        {
            return Reflector.CallMethod(_loader, "LoadInstance", parent);
        }

        public IEnumerable GetChildren(ITrackState parent)
        {
            var children = Reflector.CallMethod(_loader, "LoadCollection", parent);
            return children as IEnumerable;
        }

        public LazyLoadingProxy(Type loaderType, string repositoryName, Type parentType, Type childType)
        {
            _childType = childType;
            _parentType = parentType;
            _loaderType = loaderType.MakeGenericType(childType, parentType);
            _loader = Activator.CreateInstance(_loaderType, repositoryName);
            _repositoryName = repositoryName;
        }
    }

    public class DatabaseLazyLoader<T, S> : BaseLazyLoader<T,S>
        where T : class, ITrackState, new()
        where S : class, ITrackState, new()
    {
        protected DatabaseRepository _repository;

        public override T LoadInstance(S parent)
        {
            return _repository.GetRelative<T, S>((S)parent);
        }

        public override IEnumerable<T> LoadCollection(S parent)
        {
            return _repository.GetRelatives<T, S>((S)parent);
        }

        public DatabaseLazyLoader(string repositoryName) : base(repositoryName)
        {
            _repository = new DatabaseRepository(repositoryName);
        }
    }
}